<?php
#
# dmBridge: a data access framework for CONTENTdm(R)
#
# Copyright © 2009, 2010, 2011 Board of Regents of the Nevada System of Higher
# Education, on behalf of the University of Nevada, Las Vegas
#

/**
 * @author Alex Dolski <alex.dolski@unlv.edu>
 * @license http://www.opensource.org/licenses/mit-license.php
 */
abstract class DMAbstractQuery {

	/** @var bool */
	private $only_count = false;
	/** @var int */
	private $page = 1;
	/** @var int */
	protected $results_per_page = 20;
	/** @var array Array of DMCollections */
	private $collections = array();
	/** @var array Array of DMObjects, cached by getSearchResults() */
	protected $results = array();
	/** @var int */
	protected $num_results = 0;
	/** @var array Array of DMObjects */
	private $objects;
	/** @var array Array of DMQueryPredicate objects */
	private $predicates = array();
	/** @var Associative array of field => direction pairs */
	private $sort_fields = array();


	public function __construct() {
	}

	/**
	 * @return array Array of DMCollection objects to which the search should be
	 * limited. This will be overridden if an object is specified with
	 * <code>setObject()</code>.
	 */
	public function getCollections() {
		return $this->collections;
	}

	/**
	 * @param DMCollection collection DMCollection to which the search should be
	 * limited. This will be overridden if an object is specified with
	 * <code>setObject()</code>.
	 */
	public function addCollection(DMCollection $collection) {
		$this->collections[] = $collection;
	}

	/**
	 * @param array collections Array of DMCollection objects to which the
	 * search should be limited. This will be overridden if an object is
	 * specified with <code>setObject()</code>.
	 * @throws DMIllegalArgumentException
	 */
	public function setCollections(array $collections) {
		foreach ($collections as $c) {
			if (!$c instanceof DMCollection) {
				throw new DMIllegalArgumentException(
					DMLocalizedString::getString("INVALID_COLLECTION"));
			}
		}
		$this->collections = $collections;
	}

	/**
	 * @return void
	 */
	public function unsetCollections() {
		$this->collections = array();
	}

	/**
	 * @return boolean Whether the query should retrieve only the count of
	 * results
	 */
	public function onlyCount() {
		return $this->only_count;
	}

	/**
	 * Alias of getNumResultsPerPage().
	 *
	 * @return int
	 */
	public function getLimit() {
		return $this->results_per_page;
	}

	/**
	 * @param int limit
	 */
	public function setLimit($limit) {
		$this->results_per_page = abs($limit);
	}

	/**
	 * @param bool bool Whether the query should retrieve only the count of
	 * results
	 */
	public function setOnlyCount($bool) {
		$this->only_count = (bool) $bool;
	}

	/**
	 * @return int Number of pages spanned by the result set
	 */
	public function getNumPages() {
		if ($this->getNumResultsPerPage() > 0) {
			return ceil($this->getNumResults() / $this->getNumResultsPerPage());
		}
		return 0;
	}

	/**
	 * @return int Number of results in the result set
	 */
	public function getNumResults() {
		return $this->num_results;
	}

	/**
	 * @param int int Total number of results in the result set
	 */
	protected function setNumResults($int) {
		$this->num_results = abs($int);
	}

	/**
	 * @return int
	 * @deprecated Use getLimit() instead.
	 */
	public function getNumResultsPerPage() {
		return $this->getLimit();
	}

	/**
	 * @param int rpp Results per page
	 * @deprecated Use setLimit() instead.
	 */
	public function setNumResultsPerPage($rpp) {
		$this->setLimit($rpp);
	}

	/**
	 * @param DMObject obj An object to which the search should be limited. This
	 * will override any collections to which the search should be limited.
	 */
	public function addObject(DMObject $obj) {
		$this->objects[] = $obj;
	}

	/**
	 * @return array Array of DMObjects to which the search should be limited.
	 * This will override any collections to which the search should be limited.
	 */
	public function getObjects() {
		return $this->objects;
	}

	/**
	 * @return int The current page number
	 */
	public function getPage() {
		return $this->page;
	}

	/**
	 * @param int int
	 */
	public function setPage($int) {
		$this->page = abs((int) substr($int, 0, 8));
		if ($this->page < 1) {
			$this->page = 1;
		}
	}

	/**
	 * @param DMQueryPredicate predicate
	 */
	public function addPredicate(DMQueryPredicate $predicate) {
		$this->predicates[] = $predicate;
	}

	/**
	 * @param int index Retrieve only the DMQueryPredicate at this array index
	 * (optional)
	 * @return Array of DMQueryPredicate objects
	 */
	public function getPredicates($index = null) {
		if (array_key_exists($index, $this->predicates)) {
			return $this->predicates[$index];
		}
		return $this->predicates;
	}

	/**
	 * @param array predicates Array of DMQueryPredicate objects
	 * @throws DMIllegalArgumentException
	 */
	public function setPredicates(array $predicates) {
		$this->unsetPredicates();
		foreach ($predicates as $t) {
			if ($t instanceof DMQueryPredicate) {
				$this->addPredicate($t);
			} else {
				throw new DMIllegalArgumentException();
			}
		}
	}

	/**
	 * @return void
	 */
	public function unsetPredicates() {
		$this->predicates = array();
	}

	/**
	 * @return Associative array of field-direction pairs, e.g.
	 * "title" => "asc" or "descri" => "desc"
	 */
	public function getSortFields() {
		return $this->sort_fields;
	}

	/**
	 * @param array fields Associative array of field-direction pairs, e.g.
	 * "title" => "asc" or "descri" => "desc"
	 */
	public function setSortFields(array $fields) {
		$this->sort_fields = $fields;
	}

	/**
	 * @return int
	 */
	public function getStart() {
		return ($this->getPage() - 1) * $this->getNumResultsPerPage();
	}

}
